package com.unittec.drainage.provider.manage.utils.coordinates;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.unittec.drainage.provider.manage.utils.JtsUtils;
import com.unittec.drainage.sdk.root.internal.exception.BusinessException;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author : 程杰
 * @version V1.0
 * @Project: zkgis-merger-parent
 * @Package com.unittec.zkgis.provider.gis.util
 * @Description: TODO
 * @date Date : 2020年09月05日 0:34
 */
public class CoordinatesUtils {

    /**
     * 坐标转换成TwoCoordinates
     * 
     * @param coordinates
     * @return
     */
    public static TwoCoordinates getTwoCoordinates(String coordinates) {
        TwoCoordinates twoCoordinates = new TwoCoordinates();
        if (StringUtils.isNotBlank(coordinates)) {
            String[] array = coordinates.split(",");
            twoCoordinates.setX1(Double.valueOf(array[0]));
            twoCoordinates.setY1(Double.valueOf(array[1]));
            twoCoordinates.setX2(Double.valueOf(array[2]));
            twoCoordinates.setY2(Double.valueOf(array[3]));
        }
        return twoCoordinates;
    }

    /**
     * 坐标转换
     * @param coordinates
     * @return
     */
    public static String getCoordinates(String coordinates) {
        String[] array = coordinates.split(",");
        StringBuilder builder = new StringBuilder();
        if(array.length > 0){
            for (int i = 0; i < array.length; i++) {
                builder.append(array[i]);
                if(i != array.length - 1){
                    builder.append(i%2 == 0 ? " " : ",");
                }
            }
        }
        return builder.toString();
    }

    /**
     * Geometry转换成JSONArray
     *
     * @param geometry
     * @return
     */
    public static JSONArray GeometrySwitchByCoordinate(Geometry geometry) {
        JSONArray jsonArray = new JSONArray();
        Coordinate coordinate = geometry.getCoordinate();
        jsonArray.add(coordinate.x);
        jsonArray.add(coordinate.y);
        return jsonArray;
    }

    /**
     * Geometry转换成JSONArray
     * 
     * @param geometry
     * @return
     */
    public static JSONArray GeometrySwitchByCoordinates(Geometry geometry) {
        JSONArray jsonFatherArray = new JSONArray();
        Coordinate[] coordinateArray = geometry.getCoordinates();
        for (Coordinate coordinate : coordinateArray) {
            JSONArray jsonSonArray = new JSONArray();
            jsonSonArray.add(coordinate.x);
            jsonSonArray.add(coordinate.y);
            jsonFatherArray.add(jsonSonArray);
        }
        return jsonFatherArray;
    }

    /**
     * list转化成JSONArray
     *
     * @param list
     * @return
     */
    public static JSONArray listSwitchByCoordinates(List<Coordinate> list) {
        JSONArray jsonFatherArray = new JSONArray();
        for (Coordinate coordinate : list) {
            JSONArray jsonSonArray = new JSONArray();
            jsonSonArray.add(coordinate.x);
            jsonSonArray.add(coordinate.y);
            jsonFatherArray.add(jsonSonArray);
        }
        return jsonFatherArray;
    }

    public static List<JSONArray> coordinateConversion(String sourceCode, String targetCode, List<JSONArray> sourceCoordinateList) {
        List<JSONArray> targetCoordinateList = new ArrayList<>();
        for (JSONArray jsonArray : sourceCoordinateList) {
            targetCoordinateList.add(getCoordinate(sourceCode, targetCode, Double.valueOf(jsonArray.get(0).toString()), Double.valueOf(jsonArray.get(1).toString())));
        }
        return targetCoordinateList;
    }

    public static JSONArray getCoordinate(String sourceCode, String targetCode, Double x, Double y) {
        JSONArray jsonArray = new JSONArray();
        org.locationtech.jts.geom.Coordinate targetCoordinate = null;
        try {
            org.locationtech.jts.geom.Coordinate sourceCoordinate = new org.locationtech.jts.geom.Coordinate(x, y);
            CoordinateReferenceSystem source = CRS.decode(sourceCode);
            CoordinateReferenceSystem target = CRS.decode(targetCode);
            MathTransform transform = CRS.findMathTransform(source, target, true);
            targetCoordinate = new org.locationtech.jts.geom.Coordinate();
            JTS.transform(sourceCoordinate, targetCoordinate, transform);
        } catch (FactoryException | org.opengis.referencing.operation.TransformException e) {
            e.printStackTrace();
        }
        DecimalFormat fm = new DecimalFormat("0.0000000");
        jsonArray.add(Double.valueOf(fm.format(targetCoordinate.x)));
        jsonArray.add(Double.valueOf(fm.format(targetCoordinate.y)));
        return jsonArray;
    }

    public static IPage<Map<String, Object>> geomChangeCoordinate(String major, IPage<Map<String, Object>> page) {
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            for (Map<String, Object> map : page.getRecords()) {
                String wkt = map.get("geom") == null ? null : map.get("geom").toString();
                if (wkt != null) {
                    Geometry geometry = JtsUtils.getGeometryFromWkt(wkt);
                    if (geometry != null) {
                        Map<String, Object> geom = new HashMap<>(16);
                        geom.put("major", major);
                        geom.put("coordinate", CoordinatesUtils.GeometrySwitchByCoordinates(geometry));
                        map.put("geom", geom);
                    }
                }
            }
        }
        return page;
    }

    public static List<Map<String, Object>> geomChangeCoordinate(String major, List<Map<String, Object>> list) {
        if (CollectionUtils.isNotEmpty(list)) {
            for (Map<String, Object> map : list) {
                String wkt = map.get("geom") == null ? null : map.get("geom").toString();
                if (wkt != null) {
                    Geometry geometry = JtsUtils.getGeometryFromWkt(wkt);
                    if (geometry != null) {
                        Map<String, Object> geom = new HashMap<>(16);
                        geom.put("major", major);
                        geom.put("coordinate", CoordinatesUtils.GeometrySwitchByCoordinates(geometry));
                        map.put("geom", geom);
                    }
                }
            }
        }
        return list;
    }

    public static IPage<Map<String, Object>> geomChangeCoordinate(IPage<Map<String, Object>> page) {
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            for (Map<String, Object> map : page.getRecords()) {
                String wkb = map.get("geom") == null ? null : map.get("geom").toString();
                if (wkb != null) {
                    Geometry geometry = JtsUtils.getGeometryFromWkb(wkb);
                    if (geometry != null) {
                        Map<String, Object> geom = new HashMap<>(16);
                        geom.put("coordinate", CoordinatesUtils.GeometrySwitchByCoordinates(geometry));
                        map.put("geom", geom);
                    }
                }
            }
        }
        return page;
    }

    public static List<Map<String, Object>> geomChangeCoordinate(List<Map<String, Object>> list) {
        if (CollectionUtils.isNotEmpty(list)) {
            for (Map<String, Object> map : list) {
                String wkb = map.get("geom") == null ? null : map.get("geom").toString();
                if (wkb != null) {
                    Geometry geometry = JtsUtils.getGeometryFromWkb(wkb);
                    if (geometry != null) {
                        Map<String, Object> geom = new HashMap<>(16);
                        geom.put("coordinate", CoordinatesUtils.GeometrySwitchByCoordinates(geometry));
                        map.put("geom", geom);
                    }
                }
            }
        }
        return list;
    }

    public static Map<String, Object> geomChangeCoordinate(Map<String, Object> map) {
        if (map != null) {
            String wkb = map.get("geom") == null ? null : map.get("geom").toString();
            if (wkb != null) {
                Geometry geometry = JtsUtils.getGeometryFromWkb(wkb);
                if (geometry != null) {
                    Map<String, Object> geom = new HashMap<>(16);
                    geom.put("coordinate", CoordinatesUtils.GeometrySwitchByCoordinates(geometry));
                    map.put("geom", geom);
                }
            }
        }
        return map;
    }

    /**
     * 多点生成面
     *
     * @param coordinates
     * @return
     */
    public static Geometry initPolygonGeometry(JSONArray coordinates) {
        List<Geometry> pointList = new ArrayList<>();
        if (coordinates != null && coordinates.size() > 0) {
            for (int i = 0; i < coordinates.size(); i++) {
                JSONArray coordinate = coordinates.getJSONArray(i);
                if (coordinate != null && coordinate.size() > 0) {
                    if (coordinate.size() == 1 || coordinate.size() > 2) {
                        throw new BusinessException("多点坐标参数不正确");
                    }
                    Geometry point = JtsUtils.createPoint(coordinate.getDouble(0), coordinate.getDouble(1), JtsUtils.SRID_4547);
                    // 添加点
                    pointList.add(point);
                }
            }
        }
        // 生成面
        return JtsUtils.createPolygon(pointList, JtsUtils.SRID_4547);
    }

    /**
     * 生成点
     *
     * @param coordinates
     * @return
     */
    public static Geometry initPointGeometry(JSONArray coordinates) {

        return JtsUtils.createPoint(coordinates.getDouble(0), coordinates.getDouble(1), JtsUtils.SRID_4547);
    }
}